# Copyright 2020 by Kurt Rathjen. All Rights Reserved.
#
# This library is free software: you can redistribute it and/or modify it 
# under the terms of the GNU Lesser General Public License as published by 
# the Free Software Foundation, either version 3 of the License, or 
# (at your option) any later version. This library is distributed in the 
# hope that it will be useful, but WITHOUT ANY WARRANTY; without even the 
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
# See the GNU Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library. If not, see <http://www.gnu.org/licenses/>.

import os
import logging

from FXstudiovendor.Qt import QtGui
from FXstudiovendor.Qt import QtCore
from FXstudiovendor.Qt import QtWidgets

import FXstudioqt
import FXstudiolibrary.widgets

try:
	import FXmutils
	import FXmutils.gui
	import maya.cmds
except ImportError as error:
	print(error)


logger = logging.getLogger(__name__)


class BaseSaveWidget(QtWidgets.QWidget):

	"""Base widget for saving new items."""

	def __init__(self, item, parent=None):
		"""
		:type item: FXstudiolibrarymaya.BaseItem
		:type parent: QtWidgets.QWidget or None
		"""
		QtWidgets.QWidget.__init__(self, parent)

		self.setObjectName("studioLibraryBaseSaveWidget")
		self.setWindowTitle("Save Item")

		FXstudioqt.loadUi(self)

		self._item = item
		self._scriptJob = None
		self._formWidget = None

		widget = self.createTitleWidget()
		widget.ui.menuButton.hide()
		self.ui.titleFrame.layout().addWidget(widget)

		self.ui.acceptButton.clicked.connect(self.accept)
		self.ui.selectionSetButton.clicked.connect(self.showSelectionSetsMenu)

		try:
			self.setScriptJobEnabled(True)
		except NameError as error:
			logger.exception(error)

		self.createSequenceWidget()
		self.updateThumbnailSize()
		self.setItem(item)

	def showMenu(self):
		"""
		Show the edit menu at the current cursor position.

		:rtype: QtWidgets.QAction
		"""
		raise NotImplementedError("The title menu is not implemented")

	def createTitleWidget(self):
		"""
		Create a new instance of the title bar widget.

		:rtype: QtWidgets.QFrame
		"""

		class UI(object):
			"""Proxy class for attaching ui widgets as properties."""
			pass

		titleWidget = QtWidgets.QFrame(self)
		titleWidget.setObjectName("titleWidget")
		titleWidget.ui = UI()

		vlayout = QtWidgets.QVBoxLayout(self)
		vlayout.setSpacing(0)
		vlayout.setContentsMargins(0, 0, 0, 0)

		hlayout = QtWidgets.QHBoxLayout(self)
		hlayout.setSpacing(0)
		hlayout.setContentsMargins(0, 0, 0, 0)

		vlayout.addLayout(hlayout)

		titleButton = QtWidgets.QLabel(self)
		titleButton.setText(self.item().NAME)
		titleButton.setObjectName("titleButton")
		titleWidget.ui.titleButton = titleButton

		hlayout.addWidget(titleButton)

		menuButton = QtWidgets.QPushButton(self)
		menuButton.setText("...")
		menuButton.setObjectName("menuButton")
		titleWidget.ui.menuButton = menuButton

		hlayout.addWidget(menuButton)

		titleWidget.setLayout(vlayout)

		return titleWidget

	def createSequenceWidget(self):
		"""Create a sequence widget to replace the static thumbnail widget."""
		theme = None
		if self.parent():
			try:
				theme = self.parent().theme()
			except AttributeError as error:
				logger.debug("Cannot find theme for parent.")

		self.ui.thumbnailButton = FXstudiolibrary.widgets.ImageSequenceWidget(self, theme=theme)
		self.ui.thumbnailButton.setObjectName("thumbnailButton")
		self.ui.thumbnailFrame.layout().insertWidget(0, self.ui.thumbnailButton)
		self.ui.thumbnailButton.clicked.connect(self.thumbnailCapture)
		text = "Click to capture a thumbnail from the current model panel.\n" \
			   "CTRL + Click to show the capture window for better framing."

		self.ui.thumbnailButton.setToolTip(text)

		path = FXstudiolibrary.resource.get("icons", "camera.svg")
		self.ui.thumbnailButton.addAction(
			path,
			"Capture new image",
			"Capture new image",
			self.thumbnailCapture
		)

		path = FXstudiolibrary.resource.get("icons", "expand.svg")
		self.ui.thumbnailButton.addAction(
			path,
			"Show Capture window",
			"Show Capture window",
			self.showCaptureWindow
		)

		path = FXstudiolibrary.resource.get("icons", "folder.svg")
		self.ui.thumbnailButton.addAction(
			path,
			"Load image from disk",
			"Load image from disk",
			self.showBrowseImageDialog
		)

		icon = FXstudiolibrary.resource.icon("thumbnail_solid.png")
		self.ui.thumbnailButton.setIcon(icon)

	def setLibraryWindow(self, libraryWindow):
		"""
		Set the library widget for the item.
		
		:type libraryWindow: FXstudiolibrary.LibraryWindow
		:rtype: None
		"""
		self.item().setLibraryWindow(libraryWindow)

	def libraryWindow(self):
		"""
		Get the library widget for the item.

		:rtype: libraryWindow: FXstudiolibrary.LibraryWindow
		"""
		return self.item().libraryWindow()

	def formWidget(self):
		"""
		Get the form widget instance.

		:rtype: FXstudiolibrary.widgets.formwidget.FormWidget
		"""
		return self._formWidget

	def item(self):
		"""
		Get the library item to be created.

		:rtype: FXstudiolibrarymaya.BaseItem
		"""
		return self._item

	def setItem(self, item):
		"""
		Set the item to be created.

		:type item: FXstudiolibrarymaya.BaseItem
		"""
		self._item = item

		if os.path.exists(item.imageSequencePath()):
			self.setThumbnailPath(item.imageSequencePath())
		elif not item.isTHUMBNAIL_PATH():
			self.setThumbnailPath(item.thumbnailPath())

		schema = item.saveSchema()
		if schema:
			formWidget = FXstudiolibrary.widgets.FormWidget(self)
			formWidget.setSchema(schema)
			formWidget.setValidator(item.saveValidator)

			# Used when overriding the item
			name = os.path.basename(item.path())
			formWidget.setValues({"name": name})

			self.ui.optionsFrame.layout().addWidget(formWidget)
			self._formWidget = formWidget

			formWidget.validate()
		else:
			self.ui.optionsFrame.setVisible(False)

	def showSelectionSetsMenu(self):
		"""
		Show the selection sets menu for the current folder path.

		:rtype: None
		"""
		from FXstudiolibrarymaya import setsmenu

		path = self.folderPath()
		position = QtGui.QCursor().pos()
		libraryWindow = self.libraryWindow()

		menu = setsmenu.SetsMenu.fromPath(path, libraryWindow=libraryWindow)
		menu.exec_(position)

	def close(self):
		"""Overriding the close method to disable the script job on close."""
		self._formWidget.savePersistentValues()
		self.setScriptJobEnabled(False)
		QtWidgets.QWidget.close(self)

	def scriptJob(self):
		"""
		Get the script job object used when the users selection changes.

		:rtype: FXmutils.ScriptJob
		"""
		return self._scriptJob

	def setScriptJobEnabled(self, enabled):
		"""Set the script job used when the users selection changes."""
		if enabled:
			if not self._scriptJob:
				event = ['SelectionChanged', self.selectionChanged]
				self._scriptJob = FXmutils.ScriptJob(event=event)
		else:
			sj = self.scriptJob()
			if sj:
				sj.kill()
			self._scriptJob = None

	def resizeEvent(self, event):
		"""
		Overriding to adjust the image size when the widget changes size.

		:type event: QtCore.QSizeEvent
		"""
		self.updateThumbnailSize()

	def updateThumbnailSize(self):
		"""Update the thumbnail button to the size of the widget."""
		width = self.width() - 10
		if width > 250:
			width = 250

		size = QtCore.QSize(width, width)
		self.ui.thumbnailButton.setIconSize(size)
		self.ui.thumbnailButton.setMaximumSize(size)
		self.ui.thumbnailFrame.setMaximumSize(size)

	def setFolderPath(self, path):
		"""
		Set the destination folder path.

		:type path: str
		"""
		self.formWidget().setValue("folder", path)

	def folderPath(self):
		"""
		Return the folder path.

		:rtype: str
		"""
		return self.formWidget().value("folder")

	def selectionChanged(self):
		"""Triggered when the Maya selection changes."""
		if self.formWidget():
			self.formWidget().validate()

	def showByFrameDialog(self):
		"""
		Show the by frame dialog.

		:rtype: None or QtWidgets.QDialogButtonBox.StandardButton
		"""
		result = None
		text = 'To help speed up the playblast you can set the "by frame" ' \
			   'to a number greater than 1. For example if the "by frame" ' \
			   'is set to 2 it will playblast every second frame.'

		options = self.formWidget().values()
		byFrame = options.get("byFrame", 1)
		startFrame, endFrame = options.get("frameRange", [None, None])

		duration = 1
		if startFrame is not None and endFrame is not None:
			duration = endFrame - startFrame

		if duration > 100 and byFrame == 1:

			buttons = [
				QtWidgets.QDialogButtonBox.Ok,
				QtWidgets.QDialogButtonBox.Cancel
			]

			result = FXstudiolibrary.widgets.MessageBox.question(
				self.libraryWindow(),
				title="Playblast Tip",
				text=text,
				buttons=buttons,
				enableDontShowCheckBox=True,
			)

		return result

	def showBrowseImageDialog(self):
		"""Show a file dialog for choosing an image from disc."""
		fileDialog = QtWidgets.QFileDialog(
			self,
			caption="Open Image",
			filter="Image Files (*.png *.jpg)"
		)

		fileDialog.fileSelected.connect(self.setThumbnailPath)
		fileDialog.exec_()

	def showCaptureWindow(self):
		"""Show the capture window for framing."""
		self.thumbnailCapture(show=True)

	def setThumbnailPath(self, path):
		"""
		Set the path to the thumbnail image or the image sequence directory.

		:type path: str
		"""
		filename, extension = os.path.splitext(path)
		dst = FXstudiolibrary.tempPath("thumbnail" + extension)

		FXstudiolibrary.copyPath(path, dst, force=True)

		self.ui.thumbnailButton.setPath(dst)

	def _capturedCallback(self, src):
		"""
		Triggered when capturing a thumbnail snapshot.

		:type src: str
		"""
		path = os.path.dirname(src)
		self.setThumbnailPath(path)

	def thumbnailCapture(self, show=False):
		"""Capture a playblast and save it to the temp thumbnail path."""
		options = self.formWidget().values()
		startFrame, endFrame = options.get("frameRange", [None, None])
		step = options.get("byFrame", 1)

		# Ignore the by frame dialog when the control modifier is pressed.
		if not FXstudioqt.isControlModifier():
			result = self.showByFrameDialog()
			if result == QtWidgets.QDialogButtonBox.Cancel:
				return

		try:
			path = FXstudiolibrary.tempPath("sequence", "thumbnail.jpg")
			FXmutils.gui.thumbnailCapture(
				show=show,
				path=path,
				startFrame=startFrame,
				endFrame=endFrame,
				step=step,
				clearCache=True,
				captured=self._capturedCallback,
			)

		except Exception as e:
			title = "Error while capturing thumbnail"
			FXstudiolibrary.widgets.MessageBox.critical(self.libraryWindow(), title, str(e))
			raise

	def showThumbnailCaptureDialog(self):
		"""
		Ask the user if they would like to capture a thumbnail.

		:rtype: int
		"""
		title = "Create a thumbnail"
		text = "Would you like to capture a thumbnail?"

		buttons = [
			QtWidgets.QDialogButtonBox.Yes,
			QtWidgets.QDialogButtonBox.Ignore,
			QtWidgets.QDialogButtonBox.Cancel
		]


		parent = self.item().libraryWindow()
		button = FXstudiolibrary.widgets.MessageBox.question(
			parent,
			title,
			text,
			buttons=buttons
		)

		if button == QtWidgets.QDialogButtonBox.Yes:
			self.thumbnailCapture()
		return button

	def accept(self):
		"""Triggered when the user clicks the save button."""
		try:
			self.formWidget().validate()
			"""
			jesus

			if self.formWidget().hasErrors():
				raise Exception("\n".join(self.formWidget().errors()))
			"""

			hasFrames = self.ui.thumbnailButton.hasFrames()
			if not hasFrames:
				button = self.showThumbnailCaptureDialog()
				if button == QtWidgets.QDialogButtonBox.Cancel:
					return

			name = self.formWidget().value("name")
			folder = self.formWidget().value("folder")
			path = folder + "/" + name
			thumbnail = self.ui.thumbnailButton.firstFrame()

			self.save(path=path, thumbnail=thumbnail)

		except Exception as e:
			FXstudiolibrary.widgets.MessageBox.critical(
				self.libraryWindow(),
				"Error while saving",
				str(e),
			)
			raise

	def save(self, path, thumbnail):
		"""
		Save the item with the given objects to the given disc location path.

		:type path: str
		:type thumbnail: str
		"""
		kwargs = self.formWidget().values()
		sequencePath = self.ui.thumbnailButton.dirname()

		item = self.item()
		item.setPath(path)
		item.safeSave(
			thumbnail=thumbnail,
			sequencePath=sequencePath,
			**kwargs
		)
		self.close()
